<?php
# Base class for the RAWS interface classes.
#
# Copyright (C) 2008 rambla.be
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

/**
 * @file
 * Implementation of the Raws base class and helpers.
 */

require_once 'Zend/Gdata.php';
require_once 'Zend/Gdata/App.php';
require_once dirname(__FILE__) . '/Raws/Feed.php';
require_once dirname(__FILE__) . '/Raws/Entry.php';
require_once dirname(__FILE__) . '/Util.php';
require_once dirname(__FILE__) . '/Raws/Response.php';


/**
 * Get the URL in the enclosure link.
 *
 * @param Raws_Entry $entry Object containing ATOM entry.
 * @return string URL inside the enclosure link, or null.
 */
function get_enclosure_url_from_entry($entry) {
  $url = null;
  foreach($entry->link as $link) {
    if ($link->rel == "enclosure") {
      $url = $link->href;
    }
  }
  return $url;
}

/**
 * Helper class; wrapper around Zend_Http_Client.
 **/
class RawsHttpClient extends Zend_Http_Client
{
  public function setResponse($response) {
    $this->last_response = $response;
  }  
}

/**
 * Base class for RAWS interface classes.
 **/
class Raws extends Zend_Gdata_App
{
  protected $_base_uri = null;
  protected $_path = null;
  protected $_user = null;
  protected $_pwd = null;

  /**
   * Service name for use with Google's authentication mechanisms
   *
   * @var string
   */
  const AUTH_SERVICE_NAME = 'raws_api';

  /**
   * Default URI to which to POST.
   *
   * @var string
   */
  protected $_defaultPostUri = null;

  /**
   * Packages to search for classes when using magic __call method, in order.
   *
   * @var array
   */
  protected $_registeredPackages = array(
          'Raws',
          'Raws_Extension',
          'Rass',
          'Rass_Extension',
          'Rams',
          'Rams_Extension',
          'Rats',
          'Rats_Extension',
          'Zend_Gdata_App_Extension',
          'Zend_Gdata_App');

  /**
   * Namespaces used for GData data
   *
   * @var array
   */
  public static $namespaces = array(
    'raws' => 'http://rambla.be/raws/ns-metadata/1.0');

  /**
   * Create Raws object
   *
   * @param Zend_Http_Client $client
   * @param string $applicationId The identity of the app in the form of Company-AppName-Version
   */
  public function __construct($user = null, $pwd = null, $base_uri = null, $path = null, $client = null, $applicationId = 'MyCompany-MyApp-1.0', $ssl = False)
  {
    $tmpclient = new RawsHttpClient();
    
    $tmpclient->setConfig(array(
        'maxredirects' => 0,
        'timeout'      => 300,
        'keepalive'    => true));
    parent::__construct($tmpclient, $applicationId);
    
    $this->setBaseUri($base_uri, $ssl);
    $this->setPath($path);
    if ($user && $pwd) {
      $this->setCredentials($user, $pwd);
    }
  }
    
  public function setPath($value)
  {
     $this->_path = $value;
  }

  public function getPath()
  {
    return $this->_path;
  }

  public function getBaseUri()
  {
    return $this->_base_uri;
  }

  /**
   * Set the base uri (e.g. http://rats.enc01.rambla.be) to be used by all derived classes.
   *
   * @param string $value The base uri passed by the caller (may have the form "http://rats.enc01.rambla.be" or "rats.enc01.rambla.be")
   * @param bool $ssl Use ssl or not.
   */
  public function setBaseUri($value, $ssl = False)
  {
    if ($ssl) {
      $client = $this->getHttpClient();
      $client->setConfig(array(
        'ssltransport' => 'tls'));
    }
        
    if (False !== strpos($value, "http://")) {
      $this->_base_uri = $value;
      if ($ssl) {
        $this->_base_uri = str_replace("http://", "https://", $value);
      }
    }
    elseif (False !== strpos($value, "https://")) {
      $this->_base_uri = $value;
      if (! $ssl) {
        $this->_base_uri = str_replace("https://", "http://", $value);
      }
    }
    else { # base uri doesn't contain protocol identifier => prepend it
      if ($ssl) {
        $this->_base_uri = "https://" . $value;
      }
      else {
        $this->_base_uri = "http://" . $value;
      }
    }
    
    return $this;
  }
  
  /**
   * Change the ssl property of the client.
   *
   * @param bool $ssl Use ssl or not.
   */
  public function setSSL($ssl)
  {
    return $this->setBaseUri($this->_base_uri, $ssl);
  }
  
  public function getUser()
  {
      return $this->_user;
  }
  
  /**
   * Follow the URL stored in the 'next' link element of the feed, and return the feed in the server response (or null).
   *
   * @param Raws_Feed $feed Class derived from Raws_Feed
   * @param string $className Optional: name of the class derived from Raws_Feed.
   * @return Raws_Feed Class derived from Raws_Feed, or null.
   */
  public function getNextFeed($feed, $className = null)
  {
    # can't do anything without a feed
    if (! $feed) {
      return null; # TODO : should raise error
    }
    
    # see if there's a next link in the feed -> if so, take its url
    $url = null;
    foreach($feed->link as $link) {
      if ($link->rel == "next") {
        $url = $link->href;
      }
    }
    # No next link available -> EOF
    if (! $url) {
      return null;
    }
    
    # get the class name (= same name as the class of the original feed object)
    $className = null;
    if ($className === null && $feed instanceof Raws_Feed) {
        $className = get_class($feed);
    } elseif ($className === null) {
        $className = 'Raws_Entry';
    }

    return parent::getFeed($url, $className);
  }

  /**
   * Return the URL stored in the 'next' link element of the feed, and return the feed in the server response (or null).
   *
   * @param Raws_Feed $feed Class derived from Raws_Feed
   * @return string URL inside the 'next' link element of the feed, or null.
   */
  public function getNextLink($feed)
  {
    # can't do anything without a feed
    if (! $feed) {
      return null; # TODO : should raise error
    }
    
    # see if there's a next link in the feed -> if so, take its url
    $url = null;
    foreach($feed->link as $link) {
      if ($link->rel == "next") {
        $url = $link->href;
        break;
      }
    }
    
    return $url;
  }
  
  /**
   * Follow the URL stored in the 'last' link element of the feed, and return the feed in the server response (or null).
   *
   * @param Raws_Feed $feed Class derived from Raws_Feed
   * @param string $className Optional: name of the class derived from Raws_Feed.
   * @return Raws_Feed Class derived from Raws_Feed, or null.
   */
  public function getLastFeed($feed, $className = null)
  {
    # can't do anything without a feed
    if (! $feed) {
      return null; # TODO : should raise error
    }
    
    # see if there's a last link in the feed -> if so, take its url
    $url = null;
    foreach($feed->link as $link) {
      if ($link->rel == "last") {
        $url = $link->href;
      }
    }
    # No last link available -> EOF
    if (! $url) {
      return null;
    }
    
    # get the class name (= same name as the class of the original feed object)
    $className = null;
    if ($className === null && $feed instanceof Raws_Feed) {
        $className = get_class($feed);
    } elseif ($className === null) {
        $className = 'Raws_Entry';
    }

    return parent::getFeed($url, $className);
  }

  /**
   * Return the URL stored in the 'last' link element of the feed, and return the feed in the server response (or null).
   *
   * @param Raws_Feed $feed Class derived from Raws_Feed
   * @return string URL inside the 'next' link element of the feed, or null.
   */
  public function getLastLink($feed)
  {
    # can't do anything without a feed
    if (! $feed) {
      return null; # TODO : should raise error
    }
    
    # see if there's a last link in the feed -> if so, take its url
    $url = null;
    foreach($feed->link as $link) {
      if ($link->rel == "last") {
        $url = $link->href;
        break;
      }
    }
    
    return $url;
  }  

  /**
   * Return the URL stored in the 'next' link element of the feed, and return the feed in the server response (or null).
   *
   * @param Raws_Feed $feed Class derived from Raws_Feed
   * @return string Number of the last page.
   */
  public function getLastNr($feed)
  {
    $last_nr = null;
    $last_link = $this->getLastLink($feed);
    if ($last_link) {
      $pos = stripos($last_link, "page=");
      if ($pos !== false) {
        $tmpstr = substr($last_link, $pos + 5);
        $endpos = stripos($tmpstr, ";");
        if ($endpos !== false) {
          $last_nr = substr($tmpstr, 0, $endpos);
        } else {
          $last_nr = $page_started_str;
        }
      }
      return $last_nr;
    }
  }  

  /**
   * Change login credentials.
   *
   * @param string $user Name of the CDN user.
   * @param string $pwd Password of the CDN user.
   */
  function setCredentials($user, $pwd)
  {
    $this->_user = $user;
    $this->_pwd = $pwd;
    $client = $this->getHttpClient();
    $client->setAuth($this->_user, $this->_pwd, Zend_Http_Client::AUTH_BASIC);
    return $this;
  }
    
  function getResponse()
  {
    $client = $this->getHttpClient();
    if (!$client) {
      return null;
    }
    return $client->getLastResponse();
  }

  function getRawsResponse()
  {
    return new RawsResponse($this->getResponse());
  }
  
  public static function parseRawsResponse($response)
  {
    if (!$response) {
      return null;
    }
    return new RawsResponse($response);
  }

  function unsetSlugHeader()
  {
    # make sure the slug header is removed again (this should be in the Zend base class, let's hope next release -> see issue http://framework.zend.com/issues/browse/ZF-3515)
    $this->getHttpClient()->setHeaders('slug', null);
  }  
}
